package main.model;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.util.HashSet;
import java.util.Scanner;
import java.util.Set;
import main.controller.GEDIVAController;
import main.model.builder.CompanyBuilder;
import main.model.builder.ModelBuilder;


/**
 * Factory for building DataModels from
 *
 * @author kevingao
 *
 */
public class Factory {
    private final Set<ModelBuilder> myBuilders;

    /**
     * Constructor given a controller to use as an observer.
     *
     * @param controller Controller to receive events
     */
    public Factory (GEDIVAController controller) {
        myBuilders = new HashSet<ModelBuilder>();
        myBuilders.add(new CompanyBuilder(controller));
    }

    /**
     * Loads model from data file.
     *
     * @param dataFile File to read from
     */
    public DataModel loadModel (File dataFile) {
        try {
            // Retrieve metadata in format 'type identifier' from first line
            return loadModelFromScanner(new Scanner(dataFile), getFileExtension(dataFile));
        }
        catch (FileNotFoundException e) {
            // should not happen because File came from user selection
            e.printStackTrace();
        }
        return new NullModel();
    }

    private ModelBuilder findBuilderForType (String type) {
        for (ModelBuilder mb : myBuilders) {
            if (mb.canBuild(type)) { return mb; }
        }
        return null;
    }

    /**
     * Loads model from remote data file.
     *
     * @param dataLocation URL of the data file to load
     * @return
     */
    public DataModel loadModel (String dataLocation) {
        try {
            URL url = new URL(dataLocation);
            URLConnection conn = url.openConnection();
            return loadModelFromScanner(new Scanner(conn.getInputStream()),
                                        getFileExtension(dataLocation));
        }
        catch (MalformedURLException e) {
            System.err.println("Malformed URL: " + dataLocation);
            e.printStackTrace();
        }
        catch (IOException e) {
            System.err.println("Unable to connect to URL: " + dataLocation);
            e.printStackTrace();
        }
        return new NullModel();
    }

    private DataModel loadModelFromScanner (Scanner input, String fileExt) {
        Scanner firstLine = new Scanner(input.nextLine());
        String type = firstLine.next();

        ModelBuilder builder = findBuilderForType(type);
        // In the case that no suitable builders, return null object
        if (builder == null) { return new NullModel(); }

        // Clear old builder object
        builder.flush();
        // Set file type based on file extension (if it exists)
        if (!builder.setFileType(fileExt)) { return new NullModel(); }
        // Scan the rest of the first line for the identifier
        builder.setIdentifier(firstLine.nextLine());
        // Scan second row for headers
        builder.setHeaders(input.nextLine());

        // Loop through data rows
        while (input.hasNext()) {
            builder.build(input.nextLine());
        }
        input.close();

        // Return built object
        return builder.toModel();
    }

    private String getFileExtension (File file) {
        return getFileExtension(file.getName());
    }

    private String getFileExtension (String path) {
        final String FILE_EXT_PATTERN = ".*\\.[a-zA-Z]+$";
        if (path.matches(FILE_EXT_PATTERN)) {
            return path.substring(path.lastIndexOf('.') + 1);
        }
        else {
            return "";
        }
    }
}
